package cn.iocoder.yudao.module.crm.service.cluetransrule;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.ad.api.advertiser.AdAdvertiserApi;
import cn.iocoder.yudao.module.ad.api.advertiser.dto.AdvertiserRespDTO;
import cn.iocoder.yudao.module.ad.api.channel.AdChannelApi;
import cn.iocoder.yudao.module.ad.api.channel.dto.ClueSyncReqDTO;
import cn.iocoder.yudao.module.ad.api.channel.dto.ClueSyncRespDTO;
import cn.iocoder.yudao.module.ad.api.clue.AdClueApi;
import cn.iocoder.yudao.module.ad.api.clue.dto.ClueSaveReqDTO;
import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDistributeConfigDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.cluetranslog.ClueTransLogDO;
import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.cluetranslog.ClueTransLogMapper;
import cn.iocoder.yudao.module.crm.service.clue.CrmClueDistributeConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import cn.iocoder.yudao.module.crm.controller.admin.cluetransrule.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.cluetransrule.ClueTransRuleDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.crm.dal.mysql.cluetransrule.ClueTransRuleMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 转化规则 Service 实现类
 *
 * @author 数创万维
 */
@Service
@Validated
@Slf4j
public class ClueTransRuleServiceImpl implements ClueTransRuleService {


    @Resource
    private CrmClueDistributeConfigService clueDistributeConfigService;

    @Resource
    private ClueTransRuleMapper clueTransRuleMapper;

    @Resource
    private ClueTransLogMapper clueTransLogMapper;

    @Resource
    private CrmClueMapper crmClueMapper;

    @Resource
    private AdChannelApi adChannelApi;

    @Resource
    private AdClueApi adClueApi;

    @Resource
    private AdAdvertiserApi adAdvertiserApi;


//    @Resource
//    private AdminUserApi adminUserApi;

    @Override
    public List<String> createClueTransRule(ClueTransRuleSaveReqVO createReqVO) {

        if (CollUtil.isEmpty(createReqVO.getAdvertiserList())) {
            throw exception(new ErrorCode(100500, "请先选择已授权的广告账户"));
        }
        Map<String, List<String>> result = new HashMap<>();
        List<String> errorList = new ArrayList<>();
        createReqVO.getAdvertiserList().forEach(advertiserId -> {
            // 校验账户存在
            AdvertiserRespDTO advertiser = adAdvertiserApi.getAdvertiser(advertiserId);

            // 查询这个账户已经存在启用的规则
            if (clueTransRuleMapper.selectOne(ClueTransRuleDO::getAdvertiserId, advertiserId) != null) {
//                throw exception(new ErrorCode(500, "此账户已添加转化规则，不可重复添加"));
                errorList.add(advertiser.getAdvertiserName() + "已经存在计划，不可重复添加；");
            } else {
                ClueTransRuleDO clueTransRule = BeanUtils.toBean(createReqVO, ClueTransRuleDO.class);
                clueTransRule.setLastQueryTime(null);
                clueTransRule.setAdvertiserId(advertiserId);
                clueTransRule.setAdvertiserStrId(advertiser.getAdvertiserId());
                clueTransRule.setAdvertiserName(advertiser.getAdvertiserName());
                clueTransRule.setNextQueryTime(DateUtil.offsetMinute(new Date(), createReqVO.getMinInterval()).toLocalDateTime());
                // 默认从今年起
                clueTransRule.setLastQueryTime(DateUtil.beginOfYear(new Date()).toLocalDateTime());
                clueTransRuleMapper.insert(clueTransRule);
            }
        });

        // 返回
        return errorList;
    }

    @Override
    public void updateClueTransRule(ClueTransRuleUpdateReqVO updateReqVO) {
        // 校验存在
//        validateClueTransRuleExists(updateReqVO.getId());
        // 更新
        ClueTransRuleDO updateObj = BeanUtils.toBean(updateReqVO, ClueTransRuleDO.class);
        clueTransRuleMapper.updateById(updateObj);
    }

    @Override
    public void deleteClueTransRule(Long id) {
        // 校验存在
//        validateClueTransRuleExists(id);
        // 删除
        clueTransRuleMapper.deleteById(id);
    }

//    private void validateClueTransRuleExists(Long id) {
//        if (clueTransRuleMapper.selectById(id) == null) {
//            throw exception();
//        }
//    }

    @Override
    public ClueTransRuleDO getClueTransRule(Long id) {
        return clueTransRuleMapper.selectById(id);
    }

    @Override
    public PageResult<ClueTransRuleDO> getClueTransRulePage(ClueTransRulePageReqVO pageReqVO) {
        return clueTransRuleMapper.selectPage(pageReqVO);
    }


    /**
     * 每分钟执行一次
     *
     * @author PetePower
     * @since 2024-06-17
     */
    @PostConstruct
    @TenantIgnore
    @Scheduled(fixedRate = 1, timeUnit = TimeUnit.MINUTES)
    public void execCrmClueRule() {
        String value = SpringUtil.getProperty("yudao.job.enable");
        if (!StrUtil.equals("true", value)) {
            return ;
        }
        // 任务 获取开启的且下次执行时间小于当前时间的列表
        List<ClueTransRuleDO> executableList = clueTransRuleMapper.getExecutableList(LocalDateTime.now());
        if (CollectionUtil.isEmpty(executableList)) {
            return;
        }
        executableList.forEach(task -> {
            // 拼接起始时间和结束时间
            ClueSyncReqDTO reqDTO = new ClueSyncReqDTO();

            LocalDateTime endTime = DateUtil.offsetMinute(new Date(), -10).toLocalDateTime();
            if (task.getPageNo() == 1) {
                // 表示第1页， 使用的start/end time
                reqDTO.setStartTime(task.getLastQueryTime());
                reqDTO.setEndTime(endTime);
            } else {
                reqDTO.setStartTime(task.getLastQueryTime());
                reqDTO.setEndTime(task.getNextQueryTime());
            }
            reqDTO.setPageNo(task.getPageNo());

            // 验证已授权的账户
            reqDTO.setAdvertiserStrId(task.getAdvertiserStrId());
            // 执行线索查询
            try {
                List<ClueSyncRespDTO> clueList = adChannelApi.getClue(task.getTenantId(), task.getAccountId(), reqDTO);

                // 获取到的线索数量大于0 ，再去添加执行日志
                if (!clueList.isEmpty()) {
                    // 完成入库，插入执行日志
                    Integer total = batchInsertByTaskRule(clueList, task);
                    ClueTransLogDO logDO = new ClueTransLogDO();
                    logDO.setClueTotal(clueList.size());
                    logDO.setTransTotal(total);
                    logDO.setLastQueryTime(task.getLastQueryTime());
                    logDO.setNextQueryTime(task.getNextQueryTime());
                    logDO.setRuleId(task.getId());
                    logDO.setTenantId(task.getTenantId());
                    logDO.setAccountId(task.getAccountId());
                    TenantUtils.execute(task.getTenantId(), () -> {
                        clueTransLogMapper.insert(logDO);
                    });
                }
                if (clueList.size() == 100) {
                    // 刚好100 就表示还有下一页， 冗余一个pageNo ++ 查询下一页的
                    task.setPageNo(task.getPageNo() + 1);
                } else {
                    // 本页查询结束， 更新下次查询日期
                    task.setPageNo(1);
                    // 更新任务
                    task.setLastQueryTime(endTime);
                    task.setNextQueryTime(DateUtil.offsetMinute(new Date(), task.getMinInterval()).toLocalDateTime());
                }
                clueTransRuleMapper.updateById(task);
            } catch (Exception e) {
                log.error("线索转入程序出错： {}", e.getMessage());
            }
        });
    }

    private int batchInsertByTaskRule(List<ClueSyncRespDTO> clueList, ClueTransRuleDO task) {
        AtomicInteger total = new AtomicInteger();
        // 往线索列表里面转入，需要获取负责人
        boolean isPool = task.getTransPos() == 2;

        // 负责人
        boolean noConfig;
        if (!isPool) {
            CrmClueDistributeConfigDO distributeConfigByModule = clueDistributeConfigService.getClueDistributeConfigByModule(task.getModuleId());
            noConfig = Objects.isNull(distributeConfigByModule) || ObjectUtil.equal(distributeConfigByModule.getEnabled(), Boolean.FALSE);
        } else {
            noConfig = false;
        }
        for (ClueSyncRespDTO clue : clueList) {
            Long ownerUserId = isPool ? null : (noConfig ? null : clueDistributeConfigService.getDistributeUser(task.getModuleId()));
            try {
                ClueSaveReqDTO saveReqDTO = BeanUtils.toBean(clue, ClueSaveReqDTO.class);
                // 这里做一个去重，根据外部线索id去重
                saveReqDTO.setAccountId(task.getAccountId());
                saveReqDTO.setTenantId(task.getTenantId());
                Long adClueLogId = adClueApi.saveAdClue(saveReqDTO);
                if (Objects.nonNull(adClueLogId)) {
                    saveReqDTO.setId(adClueLogId);
                    // 检查开启了“过滤空手机号” 的配置，并且线索手机号是空的，则不插入
                    if (Objects.equals(1, task.getFilterEmptyMobile()) && StrUtil.isEmpty(saveReqDTO.getTelephone())) {
                        continue;
                    }
                    // 检查开启了“过滤空线索名称” 的配置，并且线索名称是空的，则不插入
                    if (Objects.equals(1, task.getFilterEmptyName()) && StrUtil.isEmpty(saveReqDTO.getClueName())) {
                        continue;
                    }
                    // 检查开启了“过滤重复手机号”的配置，并且线索手机号重复，则不插入
                    if (Objects.equals(1, task.getFilterRepeatMobile()) && adClueApi.getAdClueLogByMobile(task.getAccountId(), saveReqDTO.getTelephone()) > 0) {
                        continue;
                    }
                    insertToClue(saveReqDTO, ownerUserId, task.getModuleId(), task.getTenantId());
                    total.getAndIncrement();
                }
            } catch (Exception e) {
                log.error("线索入库失败： 原因: {}", e.getMessage());
            }
        }

        return total.get();
    }

    private void insertToClue(ClueSaveReqDTO clue, Long ownerUserId, Long moduleId, Long tenantId) {
        // 获得crm线索对象
        CrmClueDO crmClueDO = new CrmClueDO();
        crmClueDO.setSource(clue.getCrmSource());
        crmClueDO.setModuleId(moduleId);
        crmClueDO.setAdTrans(1);
        crmClueDO.setAdLogId(clue.getId());
        crmClueDO.setOwnerUserId(ownerUserId);
        crmClueDO.setName(clue.getClueName());
        crmClueDO.setMobile(clue.getTelephone());
        crmClueDO.setTelephone(clue.getTelephone());
        crmClueDO.setIntoPoolTime(LocalDateTime.now());
        crmClueDO.setOwnerTime(LocalDateTime.now());
        crmClueDO.setCreateTime(DateUtil.parse(clue.getClueCreateTime(), DatePattern.NORM_DATETIME_PATTERN).toLocalDateTime());
        crmClueDO.setDetailAddress(StrUtil.concat(true, clue.getProvinceName(), ",", clue.getCityName(), ",", clue.getCountyName(), ",", clue.getAddress()));
//        crmClueDO.setFollowUpStatus(clue.getFollowStatus() != 1);
        crmClueDO.setTenantId(tenantId);
        TenantUtils.execute(tenantId, () -> {
            crmClueMapper.insert(crmClueDO);
        });
    }
}